1 Introduction

This notebook contains

1.1 Packages

The packages necessary to run this notebook are the following.

library(tidyverse) # data cleaning, wrangling, plotting
library(lubridate) # dates handling
library(patchwork) # plot setup
library(plotly)    # interactive plots

# the tidyverts
library(tsibble)
library(feasts)
library(fable)
library(fable.prophet)
library(fasster)

# modeltime
library(tidymodels)
library(modeltime)

1.2 The data

The main data to be used is the daily load from the Western Regional Control Management of CENACE. We also use holidays data as to get insights on the variation.

datos <- read_csv("gcroc.csv")
festivos <- read_csv("festivos_utf8.csv")
datos <- datos %>% 
  left_join(festivos, by = c("fecha" = "fecha"))

datos <- datos %>% 
  mutate(fecha = dmy(fecha),
         dia_semana = factor(dia_semana,
                             levels = c(1:7)),
         Day_type = case_when(
           festivo %in% festivos$festivo ~ "Holiday",
           wday(fecha,week_start = 1) == 1 ~ "Monday",
           wday(fecha, week_start = 1) %in% 1:5 ~ "Weekday",
           TRUE ~ "Weekend"
         ) %>% factor(levels = c("Monday","Weekday",
                                 "Weekend","Holiday")),
         Month = month(fecha, label = TRUE) %>% factor(ordered = F)
         ) %>% 
  as_tsibble(index = fecha) %>% 
  rename(`temp min` = temp_min, 
         `temp max` = temp_max,
         `temp prom` = temp_prom)
datos

2 Exploratory Data Analysis (EDA)

2.1 Visual inspection

We begin by plotting the data in a time plot, as well as in boxplots, first by day type, and then by month, as to check if we can find differences across time.

g1 <- ggplot(datos,aes(x = fecha, y = MWh)) + xlab("")
# Time plot
p1 <- g1 + geom_line(color = "blue") + 
  ggtitle("Historic Load") 
# Day type boxplot
p2 <- g1 + geom_boxplot(aes(x = Day_type, fill = Day_type)) + 
  theme(legend.position = "none",
        axis.text.x =  element_text(angle = 45,
                                      hjust = 1)) + 
  ggtitle("Load Across Day Types")
# Month boxplot
p3 <- g1 + geom_boxplot(aes(x = Month, 
  fill = Month)
  ) + 
  theme(legend.position = "none",
        axis.text.x =  element_text(angle = 45,
                                      hjust = 1)) + 
  ggtitle("Load Across Months")
# plot group 1
pg1 <- p1 / (p2 | p3)

pg1 + plot_annotation(
  title = " Daily Electricity Load in the GCROC"
)

As can be seen from the time plot, the data exhibits a long-term upward trend, as well as indications of seasonality.

By inspecting both boxplots, we see that differences arise both across day types (whether it is a Monday, weekday, weekend or holidays), and across months, further suggesting two types of seasonality: weekly and yearly.

datos  %>%  
  features_if(is_double,features =
                         list(
       Mean = (~ mean(., na.rm = TRUE)),
       `Std. Dev.` = (~ sd(., na.rm = TRUE)),
       Min = (~ min(., na.rm = TRUE)),
       Median = (~ median(., na.rm = TRUE)),
       Max = (~ max(., na.rm = TRUE)),
       N = length)
       ) %>% 
  pivot_longer(everything()) %>% 
  separate(name, into = c("var","stat"), sep = "_") %>% 
  pivot_wider(names_from = "var",values_from = "value")

We check for the relationship between electricity load and temperature across day types.

p4 <- datos %>% 
  filter(year(fecha)>2001) %>% 
  ggplot(aes(x = `temp max`, y = MWh)) + 
  geom_point(aes(color = Day_type)) + 
  ggtitle("Daily electricity load as a function of maximum temperature") + 
  xlab("(C°)") + 
  geom_smooth(method = "lm", formula = y ~ x + I(x^2)) +
  labs(color = "") +
  theme(legend.position = "top")
  

p4

The data show a u-shape trend. Whenever the maximum temperature is low, the energy demand seems to be higher. The same happens and even in a greater degree when the maximum temperature is high.

From the image above we can see that holidays and weekends seem to be on the lower part of the plot, while mondays and weekdays tend to cluster higher. The separation between them is not as clear, and it could be because of the upward trend over the years.

We could plot each year separately to get a better look at it, or remove the trend from the series.

Plotting each year separately yields the plot below.

p4 + facet_wrap(~ factor(year(fecha))) 

Removing the trend using an STL decomposition:

p5 <- datos %>%
  mutate(detrend = MWh - datos %>% 
           model(STL(MWh)) %>% 
           components() %>% 
           pull(trend)
           ) %>% 
  ggplot(aes(x = `temp max`, y = detrend)) + 
  geom_point(aes(color = Day_type)) + 
  ggtitle("Detrended daily electricity load as a function of maximum temperature") + 
  xlab("(C°)") +
  labs(color = "") +
  theme(legend.position = "top")

p5 + 
  geom_smooth(method = "lm", formula = y ~ x + I(x^2))

p5 + 
  geom_smooth(method = "lm", formula = y ~ x + I(x^2),
              aes(color = Day_type)) 

In both cases, we can now see clearer clusters forming, supporting what we saw on the boxplots. Also, adding a global trend line or a trend line for each day type shows a similar pattern.

2.2 Data transformations

We check to see whether performing a transformation to our data could help us reduce irrelevant variation.

First, we take the log values.

p1_log <- g1 + geom_line(aes(y = log(MWh)), color = "orchid2") + 
  ggtitle("Log of historic Load") + ylab("log(MWh)")

p1 / p1_log

Now, we try using a Box-Cox transformation, choosing lambda with the Guerrero feature.

lambda <- datos %>% 
  slice_head(n = nrow(datos) - 30) %>% 
  features(MWh, features = guerrero) %>%
  pull(lambda_guerrero)

lambda
[1] 0.1032301
p1_boxcox <- g1 + geom_line(aes(y = box_cox(MWh, lambda = lambda)), color = "turquoise2") + 
  ggtitle("Historic Load with a Box-Cox transformation") + ylab(paste0("Box-Cox using lambda = ",round(lambda,digits = 4)))

p1 / p1_boxcox

3 R Packages for modeling and forecasting

We will produce forecasts using a wide variety of models, with two different R packages: fable and modeltime.

3.1 fable and the tidyverts ecosystem

A generalized function to obtain forecasts via fable is shown below. One must specify the model with as much customization as needed.

fable_workflow <- function(data = datos, model, lag = 10, dof = 0, horizon = 30, year = 2018){
  # Splitting data into train and test sets
  train <- data %>% 
    slice_head(n = (nrow(data) - horizon))

  test <- datos %>% 
    slice_tail(n = horizon)

  # fitting the model
  fable <- train %>%
    model(model)
  
  print("The fitted model:")
  fable %>% 
    report()
  
  print("Training accuracy:")
  fable %>% 
    fabletools::accuracy() %>% 
    print()
  
  # Residual diagnostics:
  resids <- fable %>% 
    gg_tsresiduals() +
    ggtitle("Residual diagnostics")
  print(resids)
  
  print("Portmanteau tests for autocorrelation")
  fable %>% 
    augment() %>% 
    features(.resid, ljung_box, lag = lag, dof = dof) %>% 
    print()
  
  
  print("The forecast:")
  fable_fcst <- fable %>% 
    forecast(h = horizon)
  print(fable_fcst)
  
  # Plotting the forecast:
  fcst <- 
    # Historic data vs. forecast
    fable_fcst %>% 
    autoplot(data) / 
    # recent history vs. forecast
    fable_fcst %>% 
    autoplot(data %>% filter(year(fecha)>year)) +
    plot_annotation(title = "The Forecast")
  print(fcst)
  
  print("Forecast accuracy:")
  fable_fcst %>% 
    fabletools::accuracy(test) %>% 
    print()
  
}

3.2 modeltime: and extension to the tidymodels

4 The models

Below we implement many of the models available in both packages.

4.1 Time series decomposition

4.1.1 .

There are many decomposition methods.

4.1.2 fable

4.1.2.1 Classical decomposition

datos %>% 
  model(classical_decomposition(MWh, type = "multiplicative")) %>% 
  components() %>% 
  autoplot() + xlab("year") +
  ggtitle("Classical additive decomposition")

4.1.2.2 STL decomposition

An STL decomposition is obtained with the following code.

datos %>% 
  model(STL(MWh)) %>% 
  components() %>% 
  autoplot() + xlab("year") +
  ggtitle("STL decomposition")

The multiple STL decomposition can be customized. In this case, we want to make the trend smoother.

datos %>% 
  model(STL(MWh ~ trend(window = 183))) %>% 
  components() %>% 
  autoplot() + xlab("year") +
  ggtitle("STL decomposition")

We could set the seasonality to be fixed specifying season(window = 'periodic').

datos %>% 
  model(STL(MWh ~ trend(window = 183) + 
              season(window = 'periodic'))) %>% 
  components() %>% 
  autoplot() + xlab("year") +
  ggtitle("STL decomposition")

  • Modeling and forecasting using STL and ARIMA:
fable_workflow(data = datos, 
               model = decomposition_model(
                 STL(box_cox(MWh, lambda = lambda) ~ trend(window = 183)),
                 ARIMA(season_adjust ~ PDQ(0,0,0))
               ))
Non-integer lag orders for random walk models are not supported. Rounding to the nearest integer.
[1] "The fitted model:"
Series: MWh 
Model: STL decomposition model 
Transformation: box_cox(.x, lambda = lambda) 
Combination: season_adjust + season_year + season_week

======================================================

Series: season_adjust + season_year 
Model: COMBINATION 
Combination: season_adjust + season_year

========================================

Series: season_adjust 
Model: ARIMA(1,1,1) w/ drift 

Coefficients:
         ar1      ma1  constant
      0.6907  -0.9618     1e-04
s.e.  0.0126   0.0057     0e+00

sigma^2 estimated as 0.006832:  log likelihood=6924.97
AIC=-13841.93   AICc=-13841.93   BIC=-13814.85

Series: season_year 
Model: SNAIVE 

sigma^2: 1e-04 


Series: season_week 
Model: SNAIVE 

sigma^2: 1e-04 

[1] "Training accuracy:"
[1] "Portmanteau tests for autocorrelation"
[1] "The forecast:"
[1] "Forecast accuracy:"

  • Using STL and ETS:
fable_workflow(data = datos, 
               model = decomposition_model(
                 STL(box_cox(MWh, lambda = lambda) ~ trend(window = 183)),
                 ETS(season_adjust ~ season("N"))
               ))
Non-integer lag orders for random walk models are not supported. Rounding to the nearest integer.
[1] "The fitted model:"
Series: MWh 
Model: STL decomposition model 
Transformation: box_cox(.x, lambda = lambda) 
Combination: season_adjust + season_year + season_week

======================================================

Series: season_adjust + season_year 
Model: COMBINATION 
Combination: season_adjust + season_year

========================================

Series: season_adjust 
Model: ETS(A,N,N) 
  Smoothing parameters:
    alpha = 0.7406011 

  Initial states:
        l
 22.38522

  sigma^2:  0.0075

     AIC     AICc      BIC 
25000.30 25000.31 25020.62 

Series: season_year 
Model: SNAIVE 

sigma^2: 1e-04 


Series: season_week 
Model: SNAIVE 

sigma^2: 1e-04 

[1] "Training accuracy:"
[1] "Portmanteau tests for autocorrelation"
[1] "The forecast:"
[1] "Forecast accuracy:"

  • Using STL, ARIMA, fourier:
fable_workflow(data = datos, 
               model = decomposition_model(
                 STL(box_cox(MWh, lambda = lambda) ~ trend(window = 183)),
                 ARIMA(season_adjust ~ PDQ(0,0,0)),
                 TSLM(season_year ~ fourier(K = 10, period = "1 year")),
                 TSLM(season_week ~ fourier(K = 2, period = "1 week"))
               ))
[1] "The fitted model:"
Series: MWh 
Model: STL decomposition model 
Transformation: box_cox(.x, lambda = lambda) 
Combination: season_adjust + season_year + season_week

======================================================

Series: season_adjust + season_year 
Model: COMBINATION 
Combination: season_adjust + season_year

========================================

Series: season_adjust 
Model: ARIMA(1,1,1) w/ drift 

Coefficients:
         ar1      ma1  constant
      0.6907  -0.9618     1e-04
s.e.  0.0126   0.0057     0e+00

sigma^2 estimated as 0.006832:  log likelihood=6924.97
AIC=-13841.93   AICc=-13841.93   BIC=-13814.85

Series: season_year 
Model: TSLM 

Residuals:
      Min        1Q    Median        3Q       Max 
-0.634312 -0.032274  0.002703  0.038800  0.251003 

Coefficients:
                                            Estimate Std. Error
(Intercept)                                0.0001739  0.0009968
fourier(K = 10, period = "1 year")C1_365  -0.1204390  0.0014061
fourier(K = 10, period = "1 year")S1_365   0.1026533  0.0014132
fourier(K = 10, period = "1 year")C2_365  -0.0474449  0.0014099
fourier(K = 10, period = "1 year")S2_365  -0.0613543  0.0014094
fourier(K = 10, period = "1 year")C3_365  -0.0007444  0.0014101
fourier(K = 10, period = "1 year")S3_365   0.0301872  0.0014092
fourier(K = 10, period = "1 year")C4_365  -0.0629057  0.0014087
fourier(K = 10, period = "1 year")S4_365  -0.0167954  0.0014106
fourier(K = 10, period = "1 year")C5_365   0.0232605  0.0014090
fourier(K = 10, period = "1 year")S5_365   0.0026676  0.0014104
fourier(K = 10, period = "1 year")C6_365  -0.0301078  0.0014098
fourier(K = 10, period = "1 year")S6_365  -0.0103454  0.0014095
fourier(K = 10, period = "1 year")C7_365  -0.0225418  0.0014093
fourier(K = 10, period = "1 year")S7_365   0.0274436  0.0014100
fourier(K = 10, period = "1 year")C8_365  -0.0282852  0.0014089
fourier(K = 10, period = "1 year")S8_365   0.0234484  0.0014104
fourier(K = 10, period = "1 year")C9_365  -0.0175749  0.0014094
fourier(K = 10, period = "1 year")S9_365   0.0099437  0.0014098
fourier(K = 10, period = "1 year")C10_365 -0.0313510  0.0014094
fourier(K = 10, period = "1 year")S10_365  0.0096697  0.0014095
                                          t value Pr(>|t|)    
(Intercept)                                 0.174   0.8615    
fourier(K = 10, period = "1 year")C1_365  -85.655  < 2e-16 ***
fourier(K = 10, period = "1 year")S1_365   72.638  < 2e-16 ***
fourier(K = 10, period = "1 year")C2_365  -33.651  < 2e-16 ***
fourier(K = 10, period = "1 year")S2_365  -43.532  < 2e-16 ***
fourier(K = 10, period = "1 year")C3_365   -0.528   0.5976    
fourier(K = 10, period = "1 year")S3_365   21.422  < 2e-16 ***
fourier(K = 10, period = "1 year")C4_365  -44.656  < 2e-16 ***
fourier(K = 10, period = "1 year")S4_365  -11.906  < 2e-16 ***
fourier(K = 10, period = "1 year")C5_365   16.509  < 2e-16 ***
fourier(K = 10, period = "1 year")S5_365    1.891   0.0586 .  
fourier(K = 10, period = "1 year")C6_365  -21.356  < 2e-16 ***
fourier(K = 10, period = "1 year")S6_365   -7.340 2.40e-13 ***
fourier(K = 10, period = "1 year")C7_365  -15.995  < 2e-16 ***
fourier(K = 10, period = "1 year")S7_365   19.464  < 2e-16 ***
fourier(K = 10, period = "1 year")C8_365  -20.076  < 2e-16 ***
fourier(K = 10, period = "1 year")S8_365   16.626  < 2e-16 ***
fourier(K = 10, period = "1 year")C9_365  -12.470  < 2e-16 ***
fourier(K = 10, period = "1 year")S9_365    7.053 1.93e-12 ***
fourier(K = 10, period = "1 year")C10_365 -22.244  < 2e-16 ***
fourier(K = 10, period = "1 year")S10_365   6.861 7.50e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.08001 on 6426 degrees of freedom
Multiple R-squared: 0.7676, Adjusted R-squared: 0.7669
F-statistic:  1061 on 20 and 6426 DF, p-value: < 2.22e-16


Series: season_week 
Model: TSLM 

Residuals:
      Min        1Q    Median        3Q       Max 
-0.209075 -0.051443  0.004141  0.053203  0.174777 

Coefficients:
                                        Estimate Std. Error t value
(Intercept)                            1.672e-06  8.368e-04   0.002
fourier(K = 2, period = "1 week")C1_7  1.834e-01  1.183e-03 154.979
fourier(K = 2, period = "1 week")S1_7 -9.024e-02  1.183e-03 -76.253
fourier(K = 2, period = "1 week")C2_7 -7.645e-02  1.183e-03 -64.598
fourier(K = 2, period = "1 week")S2_7  9.708e-02  1.183e-03  82.034
                                      Pr(>|t|)    
(Intercept)                              0.998    
fourier(K = 2, period = "1 week")C1_7   <2e-16 ***
fourier(K = 2, period = "1 week")S1_7   <2e-16 ***
fourier(K = 2, period = "1 week")C2_7   <2e-16 ***
fourier(K = 2, period = "1 week")S2_7   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.06719 on 6442 degrees of freedom
Multiple R-squared: 0.8635, Adjusted R-squared: 0.8634
F-statistic: 1.018e+04 on 4 and 6442 DF, p-value: < 2.22e-16

[1] "Training accuracy:"
[1] "Portmanteau tests for autocorrelation"
[1] "The forecast:"
[1] "Forecast accuracy:"

4.1.3 modeltime

4.2 Exponential smoothing

4.2.1 .

4.2.2 fable

fable_workflow(model = ETS(MWh, opt_crit = "mse"),
               horizon = 30,
               year = 2018)
[1] "The fitted model:"
Series: MWh 
Model: ETS(A,N,A) 
  Smoothing parameters:
    alpha = 0.9533124 
    gamma = 0.04265283 

  Initial states:
      l       s1       s2       s3       s4        s5        s6        s7
 106379 4727.049 5687.695 5698.116 4774.703 -1353.729 -16734.81 -2799.022

  sigma^2:  24853134

     AIC     AICc      BIC 
166342.7 166342.8 166410.4 
[1] "Training accuracy:"
[1] "Portmanteau tests for autocorrelation"
[1] "The forecast:"
[1] "Forecast accuracy:"

4.2.3 modeltime

4.3 ARIMA

4.3.1 .

4.3.2 fable

fable_workflow(model = ARIMA(MWh),
               horizon = 30,
               year = 2018)
[1] "The fitted model:"
Series: MWh 
Model: ARIMA(1,0,2)(2,1,0)[7] 

Coefficients:
         ar1     ma1      ma2     sar1     sar2
      0.7351  0.1529  -0.0757  -0.4803  -0.2884
s.e.  0.0158  0.0208   0.0177   0.0122   0.0120

sigma^2 estimated as 26308527:  log likelihood=-64152.01
AIC=128316   AICc=128316   BIC=128356.6
[1] "Training accuracy:"
[1] "Portmanteau tests for autocorrelation"
[1] "The forecast:"
[1] "Forecast accuracy:"

4.3.3 modeltime

4.4 Linear regression

4.4.1 .

4.4.2 fable

fable_workflow(model = TSLM(MWh ~ trend() + season()),
               horizon = 30,
               year = 2018)
[1] "The fitted model:"
Series: MWh 
Model: TSLM 

Residuals:
   Min     1Q Median     3Q    Max 
-70875  -5795   -198   6542  32277 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
(Intercept)    1.209e+05  4.050e+02 298.433   <2e-16 ***
trend()        1.228e+01  6.880e-02 178.438   <2e-16 ***
season()week2 -9.643e+02  4.791e+02  -2.013   0.0442 *  
season()week3 -7.284e+03  4.791e+02 -15.204   <2e-16 ***
season()week4 -2.364e+04  4.791e+02 -49.343   <2e-16 ***
season()week5 -7.054e+03  4.791e+02 -14.724   <2e-16 ***
season()week6 -9.198e+02  4.791e+02  -1.920   0.0549 .  
season()week7  1.202e+01  4.791e+02   0.025   0.9800    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 10280 on 6439 degrees of freedom
Multiple R-squared: 0.847,  Adjusted R-squared: 0.8469
F-statistic:  5094 on 7 and 6439 DF, p-value: < 2.22e-16
[1] "Training accuracy:"
[1] "Portmanteau tests for autocorrelation"
[1] "The forecast:"
[1] "Forecast accuracy:"

4.4.3 modeltime

4.5 Dynamic regression

4.5.1 .

4.5.2 fable

fable_workflow(model = ARIMA(MWh ~ trend() +
                               season() +
                               PDQ(0,0,0)),
               horizon = 30,
               year = 2018)
[1] "The fitted model:"
Series: MWh 
Model: LM w/ ARIMA(2,0,4) errors 

Coefficients:
         ar1     ar2     ma1      ma2      ma3      ma4  trend()  season()week2
      0.1854  0.7649  0.7259  -0.3654  -0.4059  -0.1923  12.2789      -966.8743
s.e.  0.0250  0.0239  0.0271   0.0165   0.0200   0.0128   0.4931       174.9094
      season()week3  season()week4  season()week5  season()week6  season()week7
         -7271.1371    -23630.2506     -7047.1312      -915.5542        15.3954
s.e.       240.0885       266.6915       266.6923       240.0921       174.9282
       intercept
      120848.325
s.e.    1847.866

sigma^2 estimated as 23596563:  log likelihood=-63865.91
AIC=127761.8   AICc=127761.9   BIC=127863.4
[1] "Training accuracy:"
[1] "Portmanteau tests for autocorrelation"
[1] "The forecast:"
[1] "Forecast accuracy:"

4.5.3 modeltime

4.6 Harmonic dynamic regression

4.6.1 .

4.6.2 fable

fable_workflow(model = ARIMA(box_cox(MWh, lambda) ~ fourier(period = "1 week", K = 2) + 
                               fourier(period = "1 year", K = 15) +
                               PDQ(0,0,0)),
               horizon = 30,
               year = 2018)
[1] "The fitted model:"
Series: MWh 
Model: LM w/ ARIMA(1,1,5) errors 
Transformation: box_cox(.x, lambda) 

Coefficients:
          ar1      ma1     ma2      ma3     ma4      ma5
      -0.2124  -0.3472  0.0252  -0.4941  0.1705  -0.2571
s.e.   0.0317   0.0303  0.0185   0.0105  0.0175   0.0145
      fourier(period = "1 week", K = 2)C1_7  fourier(period = "1 week", K = 2)S1_7
                                     0.1861                                -0.0917
s.e.                                 0.0027                                 0.0027
      fourier(period = "1 week", K = 2)C2_7  fourier(period = "1 week", K = 2)S2_7
                                    -0.0767                                 0.0973
s.e.                                 0.0017                                 0.0017
      fourier(period = "1 year", K = 15)C1_365  fourier(period = "1 year", K = 15)S1_365
                                       -0.1136                                     0.111
s.e.                                    0.0120                                     0.012
      fourier(period = "1 year", K = 15)C2_365  fourier(period = "1 year", K = 15)S2_365
                                       -0.0502                                   -0.0581
s.e.                                    0.0074                                    0.0074
      fourier(period = "1 year", K = 15)C3_365  fourier(period = "1 year", K = 15)S3_365
                                       -0.0027                                    0.0295
s.e.                                    0.0061                                    0.0061
      fourier(period = "1 year", K = 15)C4_365  fourier(period = "1 year", K = 15)S4_365
                                       -0.0645                                   -0.0171
s.e.                                    0.0056                                    0.0056
      fourier(period = "1 year", K = 15)C5_365  fourier(period = "1 year", K = 15)S5_365
                                        0.0202                                    0.0004
s.e.                                    0.0054                                    0.0054
      fourier(period = "1 year", K = 15)C6_365  fourier(period = "1 year", K = 15)S6_365
                                       -0.0276                                   -0.0097
s.e.                                    0.0052                                    0.0052
      fourier(period = "1 year", K = 15)C7_365  fourier(period = "1 year", K = 15)S7_365
                                       -0.0244                                    0.0242
s.e.                                    0.0051                                    0.0051
      fourier(period = "1 year", K = 15)C8_365  fourier(period = "1 year", K = 15)S8_365
                                       -0.0273                                    0.0243
s.e.                                    0.0051                                    0.0051
      fourier(period = "1 year", K = 15)C9_365  fourier(period = "1 year", K = 15)S9_365
                                       -0.0188                                    0.0114
s.e.                                    0.0050                                    0.0050
      fourier(period = "1 year", K = 15)C10_365
                                        -0.0299
s.e.                                     0.0049
      fourier(period = "1 year", K = 15)S10_365
                                         0.0095
s.e.                                     0.0050
      fourier(period = "1 year", K = 15)C11_365
                                        -0.0158
s.e.                                     0.0049
      fourier(period = "1 year", K = 15)S11_365
                                         0.0196
s.e.                                     0.0049
      fourier(period = "1 year", K = 15)C12_365
                                        -0.0198
s.e.                                     0.0049
      fourier(period = "1 year", K = 15)S12_365
                                         0.0077
s.e.                                     0.0049
      fourier(period = "1 year", K = 15)C13_365
                                        -0.0146
s.e.                                     0.0048
      fourier(period = "1 year", K = 15)S13_365
                                         0.0111
s.e.                                     0.0048
      fourier(period = "1 year", K = 15)C14_365
                                        -0.0141
s.e.                                     0.0048
      fourier(period = "1 year", K = 15)S14_365
                                         0.0163
s.e.                                     0.0048
      fourier(period = "1 year", K = 15)C15_365
                                        -0.0043
s.e.                                     0.0047
      fourier(period = "1 year", K = 15)S15_365  intercept
                                         0.0112      3e-04
s.e.                                     0.0048      1e-04

sigma^2 estimated as 0.01787:  log likelihood=3843.61
AIC=-7603.23   AICc=-7602.66   BIC=-7318.84
[1] "Training accuracy:"
[1] "Portmanteau tests for autocorrelation"
[1] "The forecast:"
[1] "Forecast accuracy:"

fable_workflow(model = ARIMA(MWh ~ fourier(period = "1 week", K = 2) + 
                               fourier(period = "1 year", K = 15) +
                               PDQ(0,0,0)),
               horizon = 30,
               year = 2018)
[1] "The fitted model:"
Series: MWh 
Model: LM w/ ARIMA(1,1,5) errors 

Coefficients:
          ar1      ma1     ma2      ma3     ma4      ma5
      -0.2156  -0.3032  0.0212  -0.4937  0.1511  -0.2752
s.e.   0.0302   0.0286  0.0178   0.0103  0.0166   0.0153
      fourier(period = "1 week", K = 2)C1_7  fourier(period = "1 week", K = 2)S1_7
                                  8249.0776                             -4040.5453
s.e.                               122.3407                               122.3205
      fourier(period = "1 week", K = 2)C2_7  fourier(period = "1 week", K = 2)S2_7
                                 -3295.3898                              4220.0251
s.e.                                72.3747                                72.3801
      fourier(period = "1 year", K = 15)C1_365  fourier(period = "1 year", K = 15)S1_365
                                    -5253.9248                                 4909.4761
s.e.                                  538.4727                                  538.0435
      fourier(period = "1 year", K = 15)C2_365  fourier(period = "1 year", K = 15)S2_365
                                    -2178.5503                                -2671.6256
s.e.                                  332.0562                                  332.1148
      fourier(period = "1 year", K = 15)C3_365  fourier(period = "1 year", K = 15)S3_365
                                       56.5035                                 1386.2932
s.e.                                  277.0965                                  277.6884
      fourier(period = "1 year", K = 15)C4_365  fourier(period = "1 year", K = 15)S4_365
                                    -2849.5388                                 -827.5499
s.e.                                  254.9897                                  255.5476
      fourier(period = "1 year", K = 15)C5_365  fourier(period = "1 year", K = 15)S5_365
                                     1073.2311                                   58.1184
s.e.                                  244.0289                                  244.1479
      fourier(period = "1 year", K = 15)C6_365  fourier(period = "1 year", K = 15)S6_365
                                    -1266.1608                                 -444.8868
s.e.                                  237.4888                                  237.5181
      fourier(period = "1 year", K = 15)C7_365  fourier(period = "1 year", K = 15)S7_365
                                     -905.8287                                  1023.350
s.e.                                  233.0168                                   233.269
      fourier(period = "1 year", K = 15)C8_365  fourier(period = "1 year", K = 15)S8_365
                                    -1130.9984                                 1046.9334
s.e.                                  229.8515                                  230.0595
      fourier(period = "1 year", K = 15)C9_365  fourier(period = "1 year", K = 15)S9_365
                                     -836.6662                                  482.3220
s.e.                                  227.4181                                  227.4204
      fourier(period = "1 year", K = 15)C10_365
                                     -1247.5351
s.e.                                   225.2296
      fourier(period = "1 year", K = 15)S10_365
                                       376.1332
s.e.                                   225.2962
      fourier(period = "1 year", K = 15)C11_365
                                      -642.8160
s.e.                                   223.2337
      fourier(period = "1 year", K = 15)S11_365
                                       753.0371
s.e.                                   223.4089
      fourier(period = "1 year", K = 15)C12_365
                                      -810.9698
s.e.                                   221.4742
      fourier(period = "1 year", K = 15)S12_365
                                       342.5265
s.e.                                   221.5219
      fourier(period = "1 year", K = 15)C13_365
                                      -604.0940
s.e.                                   219.7441
      fourier(period = "1 year", K = 15)S13_365
                                       436.8440
s.e.                                   219.7255
      fourier(period = "1 year", K = 15)C14_365
                                      -558.3188
s.e.                                   217.9458
      fourier(period = "1 year", K = 15)S14_365
                                       702.6378
s.e.                                   218.0272
      fourier(period = "1 year", K = 15)C15_365
                                      -157.1762
s.e.                                   216.1706
      fourier(period = "1 year", K = 15)S15_365  intercept
                                       408.9707    12.9355
s.e.                                   216.2393     5.9488

sigma^2 estimated as 33508727:  log likelihood=-64972.95
AIC=130029.9   AICc=130030.5   BIC=130314.3
[1] "Training accuracy:"
[1] "Portmanteau tests for autocorrelation"
[1] "The forecast:"
[1] "Forecast accuracy:"

4.6.3 modeltime

4.7 Prophet

4.7.1 .

4.7.2 fable

fable_workflow(model = prophet(MWh),
               horizon = 30,
               year = 2018)
[1] "The fitted model:"
Series: MWh 
Model: prophet 

A model specific report is not available for this model class.[1] "Training accuracy:"
[1] "Portmanteau tests for autocorrelation"
[1] "The forecast:"
[1] "Forecast accuracy:"

4.7.3 modeltime

4.8 FASSTER

4.8.1 .

4.8.2 fable

fable_workflow(model = fasster(MWh ~ fourier(period = "1 week", K = 2) +
                                 fourier(period = "1 year", K = 10)),
               horizon = 30,
               year = 2018)
[1] "The fitted model:"
Series: MWh 
Model: FASSTER 

Estimated variances:
 State noise variances (W):
  fourier(period = "1 week", K = 2)
   4.7028e-11 1.6002e-10 5.7203e-11 4.0645e-11
  fourier(period = "1 year", K = 10)
   4.5689e-04 1.6029e-04 4.3514e-04 4.5226e-04 6.1666e-04 4.8102e-04 5.0731e-04 5.0293e-04 4.3198e-04 5.8838e-04 5.4549e-04 4.4866e-04 2.7417e-04 2.9641e-04 1.1877e-04 1.4319e-04 3.3793e-05 3.6048e-05 1.4243e-06 2.1692e-06

 Observation noise variance (V):
  6.0478e+08[1] "Training accuracy:"
[1] "Portmanteau tests for autocorrelation"
[1] "The forecast:"
[1] "Forecast accuracy:"

4.8.3 modeltime

4.9 Neural network autorregresion

4.9.1 .

4.9.2 fable

fable_workflow(model = decomposition_model(
  STL(MWh ~ trend(window = 183)),
  NNETAR(season_adjust)
),
               horizon = 30,
               year = 2018)
Non-integer lag orders for random walk models are not supported. Rounding to the nearest integer.
[1] "The fitted model:"
Series: MWh 
Model: STL decomposition model 
Combination: season_adjust + season_year + season_week

======================================================

Series: season_adjust + season_year 
Model: COMBINATION 
Combination: season_adjust + season_year

========================================

Series: season_adjust 
Model: NNAR(37,1,19)[7] 

Average of 20 networks, each of which is
a 37-19-1 network with 742 weights
options were - linear output units 

sigma^2 estimated as 6385944

Series: season_year 
Model: SNAIVE 

sigma^2: 288972.6866 


Series: season_week 
Model: SNAIVE 

sigma^2: 133957.794 

[1] "Training accuracy:"
[1] "Portmanteau tests for autocorrelation"
[1] "The forecast:"
[1] "Forecast accuracy:"

fable_workflow(model = NNETAR(box_cox(MWh, lambda = lambda)),
               horizon = 30,
               year = 2018)
[1] "The fitted model:"
Series: MWh 
Model: NNAR(36,1,18)[7] 
Transformation: box_cox(.x, lambda = lambda) 

Average of 20 networks, each of which is
a 36-18-1 network with 685 weights
options were - linear output units 

sigma^2 estimated as 0.007014
[1] "Training accuracy:"
[1] "Portmanteau tests for autocorrelation"
[1] "The forecast:"
[1] "Forecast accuracy:"

4.9.3 modeltime

4.10 The proposed model

5 Comparison across models

5.1 Training adjustment

5.2 Forecasting adjustment

5.3 Cross-validation

5.4 Forecasts

6 Conclusions

LS0tDQp0aXRsZTogIkZvcmVjYXN0aW5nIGRhaWx5IGVsZWN0cmljaXR5IGxvYWQgdXNpbmcgYGZhYmxlYCBhbmQgYG1vZGVsdGltZWAiDQpzdWJ0aXRsZTogIklESS1JSS4gUGhEIGluIEVuZ2luZWVyaW5nIFNjaWVuY2VzIg0KZGF0ZTogMjAyMC0wOC0yMA0KYXV0aG9yOiAiUGFibG8gQmVuYXZpZGVzLUhlcnJlcmEiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KICAgIHRoZW1lOiBqb3VybmFsDQogICAgaGlnaGxpZ2g6IHRhbmdvDQogICAgbnVtYmVyX3NlY3Rpb25zOiBUUlVFDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEwKQ0KYGBgDQoNCg0KIyBJbnRyb2R1Y3Rpb24NCg0KVGhpcyBub3RlYm9vayBjb250YWlucyANCg0KIyMgUGFja2FnZXMNCg0KVGhlIHBhY2thZ2VzIG5lY2Vzc2FyeSB0byBydW4gdGhpcyBub3RlYm9vayBhcmUgdGhlIGZvbGxvd2luZy4NCg0KYGBge3IgcGtncywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKSAjIGRhdGEgY2xlYW5pbmcsIHdyYW5nbGluZywgcGxvdHRpbmcNCmxpYnJhcnkobHVicmlkYXRlKSAjIGRhdGVzIGhhbmRsaW5nDQpsaWJyYXJ5KHBhdGNod29yaykgIyBwbG90IHNldHVwDQpsaWJyYXJ5KHBsb3RseSkgICAgIyBpbnRlcmFjdGl2ZSBwbG90cw0KDQojIHRoZSB0aWR5dmVydHMNCmxpYnJhcnkodHNpYmJsZSkNCmxpYnJhcnkoZmVhc3RzKQ0KbGlicmFyeShmYWJsZSkNCmxpYnJhcnkoZmFibGUucHJvcGhldCkNCmxpYnJhcnkoZmFzc3RlcikNCg0KIyBtb2RlbHRpbWUNCmxpYnJhcnkodGlkeW1vZGVscykNCmxpYnJhcnkobW9kZWx0aW1lKQ0KYGBgDQoNCiMjIFRoZSBkYXRhDQoNClRoZSBtYWluIGRhdGEgdG8gYmUgdXNlZCBpcyB0aGUgZGFpbHkgbG9hZCBmcm9tIHRoZSBXZXN0ZXJuIFJlZ2lvbmFsIENvbnRyb2wgTWFuYWdlbWVudCBvZiBDRU5BQ0UuIFdlIGFsc28gdXNlIGhvbGlkYXlzIGRhdGEgYXMgdG8gZ2V0IGluc2lnaHRzIG9uIHRoZSB2YXJpYXRpb24uDQoNCmBgYHtyIGRhdGEgLSBsb2FkLCBtZXNzYWdlPUZBTFNFfQ0KZGF0b3MgPC0gcmVhZF9jc3YoImdjcm9jLmNzdiIpDQpmZXN0aXZvcyA8LSByZWFkX2NzdigiZmVzdGl2b3NfdXRmOC5jc3YiKQ0KZGF0b3MgPC0gZGF0b3MgJT4lIA0KICBsZWZ0X2pvaW4oZmVzdGl2b3MsIGJ5ID0gYygiZmVjaGEiID0gImZlY2hhIikpDQoNCmRhdG9zIDwtIGRhdG9zICU+JSANCiAgbXV0YXRlKGZlY2hhID0gZG15KGZlY2hhKSwNCiAgICAgICAgIGRpYV9zZW1hbmEgPSBmYWN0b3IoZGlhX3NlbWFuYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygxOjcpKSwNCiAgICAgICAgIERheV90eXBlID0gY2FzZV93aGVuKA0KICAgICAgICAgICBmZXN0aXZvICVpbiUgZmVzdGl2b3MkZmVzdGl2byB+ICJIb2xpZGF5IiwNCiAgICAgICAgICAgd2RheShmZWNoYSx3ZWVrX3N0YXJ0ID0gMSkgPT0gMSB+ICJNb25kYXkiLA0KICAgICAgICAgICB3ZGF5KGZlY2hhLCB3ZWVrX3N0YXJ0ID0gMSkgJWluJSAxOjUgfiAiV2Vla2RheSIsDQogICAgICAgICAgIFRSVUUgfiAiV2Vla2VuZCINCiAgICAgICAgICkgJT4lIGZhY3RvcihsZXZlbHMgPSBjKCJNb25kYXkiLCJXZWVrZGF5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrZW5kIiwiSG9saWRheSIpKSwNCiAgICAgICAgIE1vbnRoID0gbW9udGgoZmVjaGEsIGxhYmVsID0gVFJVRSkgJT4lIGZhY3RvcihvcmRlcmVkID0gRikNCiAgICAgICAgICkgJT4lIA0KICBhc190c2liYmxlKGluZGV4ID0gZmVjaGEpICU+JSANCiAgcmVuYW1lKGB0ZW1wIG1pbmAgPSB0ZW1wX21pbiwgDQogICAgICAgICBgdGVtcCBtYXhgID0gdGVtcF9tYXgsDQogICAgICAgICBgdGVtcCBwcm9tYCA9IHRlbXBfcHJvbSkNCmRhdG9zDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQojIFRvIHByaW50IGluIExhVGVYIGZvcm0NCmRhdG9zICU+JSANCiAgYXNfdGliYmxlKCkgJT4lICANCiAgbXV0YXRlKGZlY2hhID0gYXMuY2hhcmFjdGVyKGZlY2hhKSkgJT4lICBzbGljZV9oZWFkKG4gPSAxMCkgJT4lIA0KICB4dGFibGUoKSAlPiUgcHJpbnQoKQ0KYGBgDQoNCiMgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyAoRURBKQ0KDQojIyBWaXN1YWwgaW5zcGVjdGlvbg0KDQpXZSBiZWdpbiBieSBwbG90dGluZyB0aGUgZGF0YSBpbiBhIHRpbWUgcGxvdCwgYXMgd2VsbCBhcyBpbiBib3hwbG90cywgZmlyc3QgYnkgZGF5IHR5cGUsIGFuZCB0aGVuIGJ5IG1vbnRoLCBhcyB0byBjaGVjayBpZiB3ZSBjYW4gZmluZCBkaWZmZXJlbmNlcyBhY3Jvc3MgdGltZS4NCg0KDQpgYGB7ciB0aW1lLWJveCBwbG90c30NCmcxIDwtIGdncGxvdChkYXRvcyxhZXMoeCA9IGZlY2hhLCB5ID0gTVdoKSkgKyB4bGFiKCIiKQ0KIyBUaW1lIHBsb3QNCnAxIDwtIGcxICsgZ2VvbV9saW5lKGNvbG9yID0gImJsdWUiKSArIA0KICBnZ3RpdGxlKCJIaXN0b3JpYyBMb2FkIikgDQojIERheSB0eXBlIGJveHBsb3QNCnAyIDwtIGcxICsgZ2VvbV9ib3hwbG90KGFlcyh4ID0gRGF5X3R5cGUsIGZpbGwgPSBEYXlfdHlwZSkpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgYXhpcy50ZXh0LnggPSAgZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSkpICsgDQogIGdndGl0bGUoIkxvYWQgQWNyb3NzIERheSBUeXBlcyIpDQojIE1vbnRoIGJveHBsb3QNCnAzIDwtIGcxICsgZ2VvbV9ib3hwbG90KGFlcyh4ID0gTW9udGgsIA0KICBmaWxsID0gTW9udGgpDQogICkgKyANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBheGlzLnRleHQueCA9ICBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkgKyANCiAgZ2d0aXRsZSgiTG9hZCBBY3Jvc3MgTW9udGhzIikNCiMgcGxvdCBncm91cCAxDQpwZzEgPC0gcDEgLyAocDIgfCBwMykNCg0KcGcxICsgcGxvdF9hbm5vdGF0aW9uKA0KICB0aXRsZSA9ICIgRGFpbHkgRWxlY3RyaWNpdHkgTG9hZCBpbiB0aGUgR0NST0MiDQopDQpgYGANCg0KQXMgY2FuIGJlIHNlZW4gZnJvbSB0aGUgdGltZSBwbG90LCB0aGUgZGF0YSBleGhpYml0cyBhIGxvbmctdGVybSB1cHdhcmQgdHJlbmQsIGFzIHdlbGwgYXMgaW5kaWNhdGlvbnMgb2Ygc2Vhc29uYWxpdHkuDQoNCkJ5IGluc3BlY3RpbmcgYm90aCBib3hwbG90cywgd2Ugc2VlIHRoYXQgZGlmZmVyZW5jZXMgYXJpc2UgYm90aCBhY3Jvc3MgZGF5IHR5cGVzICh3aGV0aGVyIGl0IGlzIGEgTW9uZGF5LCB3ZWVrZGF5LCB3ZWVrZW5kIG9yIGhvbGlkYXlzKSwgYW5kIGFjcm9zcyBtb250aHMsIGZ1cnRoZXIgc3VnZ2VzdGluZyB0d28gdHlwZXMgb2Ygc2Vhc29uYWxpdHk6IHdlZWtseSBhbmQgeWVhcmx5Lg0KDQpgYGB7ciBzdGF0c30NCmRhdG9zICAlPiUgIA0KICBmZWF0dXJlc19pZihpc19kb3VibGUsZmVhdHVyZXMgPQ0KICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QoDQogICAgICAgTWVhbiA9ICh+IG1lYW4oLiwgbmEucm0gPSBUUlVFKSksDQogICAgICAgYFN0ZC4gRGV2LmAgPSAofiBzZCguLCBuYS5ybSA9IFRSVUUpKSwNCiAgICAgICBNaW4gPSAofiBtaW4oLiwgbmEucm0gPSBUUlVFKSksDQogICAgICAgTWVkaWFuID0gKH4gbWVkaWFuKC4sIG5hLnJtID0gVFJVRSkpLA0KICAgICAgIE1heCA9ICh+IG1heCguLCBuYS5ybSA9IFRSVUUpKSwNCiAgICAgICBOID0gbGVuZ3RoKQ0KICAgICAgICkgJT4lIA0KICBwaXZvdF9sb25nZXIoZXZlcnl0aGluZygpKSAlPiUgDQogIHNlcGFyYXRlKG5hbWUsIGludG8gPSBjKCJ2YXIiLCJzdGF0IiksIHNlcCA9ICJfIikgJT4lIA0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gInZhciIsdmFsdWVzX2Zyb20gPSAidmFsdWUiKQ0KYGBgDQoNCldlIGNoZWNrIGZvciB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZWxlY3RyaWNpdHkgbG9hZCBhbmQgdGVtcGVyYXR1cmUgYWNyb3NzIGRheSB0eXBlcy4NCg0KYGBge3IgTVdoIHYuIHRlbXAsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMH0NCnA0IDwtIGRhdG9zICU+JSANCiAgZmlsdGVyKHllYXIoZmVjaGEpPjIwMDEpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gYHRlbXAgbWF4YCwgeSA9IE1XaCkpICsgDQogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gRGF5X3R5cGUpKSArIA0KICBnZ3RpdGxlKCJEYWlseSBlbGVjdHJpY2l0eSBsb2FkIGFzIGEgZnVuY3Rpb24gb2YgbWF4aW11bSB0ZW1wZXJhdHVyZSIpICsgDQogIHhsYWIoIihDwrApIikgKyANCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgZm9ybXVsYSA9IHkgfiB4ICsgSSh4XjIpKSArDQogIGxhYnMoY29sb3IgPSAiIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikNCiAgDQoNCnA0DQpgYGANCg0KVGhlIGRhdGEgc2hvdyBhIHUtc2hhcGUgdHJlbmQuIFdoZW5ldmVyIHRoZSBtYXhpbXVtIHRlbXBlcmF0dXJlIGlzIGxvdywgdGhlIGVuZXJneSBkZW1hbmQgc2VlbXMgdG8gYmUgaGlnaGVyLiBUaGUgc2FtZSBoYXBwZW5zIGFuZCBldmVuIGluIGEgZ3JlYXRlciBkZWdyZWUgd2hlbiB0aGUgbWF4aW11bSB0ZW1wZXJhdHVyZSBpcyBoaWdoLg0KDQpGcm9tIHRoZSBpbWFnZSBhYm92ZSB3ZSBjYW4gc2VlIHRoYXQgaG9saWRheXMgYW5kIHdlZWtlbmRzIHNlZW0gdG8gYmUgb24gdGhlIGxvd2VyIHBhcnQgb2YgdGhlIHBsb3QsIHdoaWxlIG1vbmRheXMgYW5kIHdlZWtkYXlzIHRlbmQgdG8gY2x1c3RlciBoaWdoZXIuIFRoZSBzZXBhcmF0aW9uIGJldHdlZW4gdGhlbSBpcyBub3QgYXMgY2xlYXIsIGFuZCBpdCBjb3VsZCBiZSBiZWNhdXNlIG9mIHRoZSB1cHdhcmQgdHJlbmQgb3ZlciB0aGUgeWVhcnMuDQoNCldlIGNvdWxkIHBsb3QgZWFjaCB5ZWFyIHNlcGFyYXRlbHkgdG8gZ2V0IGEgYmV0dGVyIGxvb2sgYXQgaXQsIG9yIHJlbW92ZSB0aGUgdHJlbmQgZnJvbSB0aGUgc2VyaWVzLg0KDQpQbG90dGluZyBlYWNoIHllYXIgc2VwYXJhdGVseSB5aWVsZHMgdGhlIHBsb3QgYmVsb3cuDQoNCmBgYHtyfQ0KcDQgKyBmYWNldF93cmFwKH4gZmFjdG9yKHllYXIoZmVjaGEpKSkgDQpgYGANCg0KUmVtb3ZpbmcgdGhlIHRyZW5kIHVzaW5nIGFuIFNUTCBkZWNvbXBvc2l0aW9uOg0KDQpgYGB7cn0NCnA1IDwtIGRhdG9zICU+JQ0KICBtdXRhdGUoZGV0cmVuZCA9IE1XaCAtIGRhdG9zICU+JSANCiAgICAgICAgICAgbW9kZWwoU1RMKE1XaCkpICU+JSANCiAgICAgICAgICAgY29tcG9uZW50cygpICU+JSANCiAgICAgICAgICAgcHVsbCh0cmVuZCkNCiAgICAgICAgICAgKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IGB0ZW1wIG1heGAsIHkgPSBkZXRyZW5kKSkgKyANCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBEYXlfdHlwZSkpICsgDQogIGdndGl0bGUoIkRldHJlbmRlZCBkYWlseSBlbGVjdHJpY2l0eSBsb2FkIGFzIGEgZnVuY3Rpb24gb2YgbWF4aW11bSB0ZW1wZXJhdHVyZSIpICsgDQogIHhsYWIoIihDwrApIikgKw0KICBsYWJzKGNvbG9yID0gIiIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpDQoNCnA1ICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4geCArIEkoeF4yKSkNCnA1ICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4geCArIEkoeF4yKSwNCiAgICAgICAgICAgICAgYWVzKGNvbG9yID0gRGF5X3R5cGUpKSANCmBgYA0KDQpJbiBib3RoIGNhc2VzLCB3ZSBjYW4gbm93IHNlZSBjbGVhcmVyIGNsdXN0ZXJzIGZvcm1pbmcsIHN1cHBvcnRpbmcgd2hhdCB3ZSBzYXcgb24gdGhlIGJveHBsb3RzLiBBbHNvLCBhZGRpbmcgYSBnbG9iYWwgdHJlbmQgbGluZSBvciBhIHRyZW5kIGxpbmUgZm9yIGVhY2ggZGF5IHR5cGUgc2hvd3MgYSBzaW1pbGFyIHBhdHRlcm4uDQoNCiMjIERhdGEgdHJhbnNmb3JtYXRpb25zDQoNCldlIGNoZWNrIHRvIHNlZSB3aGV0aGVyIHBlcmZvcm1pbmcgYSB0cmFuc2Zvcm1hdGlvbiB0byBvdXIgZGF0YSBjb3VsZCBoZWxwIHVzIHJlZHVjZSBpcnJlbGV2YW50IHZhcmlhdGlvbi4NCg0KRmlyc3QsIHdlIHRha2UgdGhlIGxvZyB2YWx1ZXMuDQoNCmBgYHtyfQ0KcDFfbG9nIDwtIGcxICsgZ2VvbV9saW5lKGFlcyh5ID0gbG9nKE1XaCkpLCBjb2xvciA9ICJvcmNoaWQyIikgKyANCiAgZ2d0aXRsZSgiTG9nIG9mIGhpc3RvcmljIExvYWQiKSArIHlsYWIoImxvZyhNV2gpIikNCg0KcDEgLyBwMV9sb2cNCmBgYA0KDQpOb3csIHdlIHRyeSB1c2luZyBhIEJveC1Db3ggdHJhbnNmb3JtYXRpb24sIGNob29zaW5nIGxhbWJkYSB3aXRoIHRoZSBHdWVycmVybyBmZWF0dXJlLg0KDQpgYGB7cn0NCmxhbWJkYSA8LSBkYXRvcyAlPiUgDQogIHNsaWNlX2hlYWQobiA9IG5yb3coZGF0b3MpIC0gMzApICU+JSANCiAgZmVhdHVyZXMoTVdoLCBmZWF0dXJlcyA9IGd1ZXJyZXJvKSAlPiUNCiAgcHVsbChsYW1iZGFfZ3VlcnJlcm8pDQoNCmxhbWJkYQ0KDQpwMV9ib3hjb3ggPC0gZzEgKyBnZW9tX2xpbmUoYWVzKHkgPSBib3hfY294KE1XaCwgbGFtYmRhID0gbGFtYmRhKSksIGNvbG9yID0gInR1cnF1b2lzZTIiKSArIA0KICBnZ3RpdGxlKCJIaXN0b3JpYyBMb2FkIHdpdGggYSBCb3gtQ294IHRyYW5zZm9ybWF0aW9uIikgKyB5bGFiKHBhc3RlMCgiQm94LUNveCB1c2luZyBsYW1iZGEgPSAiLHJvdW5kKGxhbWJkYSxkaWdpdHMgPSA0KSkpDQoNCnAxIC8gcDFfYm94Y294DQpgYGANCg0KDQoNCg0KIyBgUmAgUGFja2FnZXMgZm9yIG1vZGVsaW5nIGFuZCBmb3JlY2FzdGluZw0KDQpXZSB3aWxsIHByb2R1Y2UgZm9yZWNhc3RzIHVzaW5nIGEgd2lkZSB2YXJpZXR5IG9mIG1vZGVscywgd2l0aCB0d28gZGlmZmVyZW50IGBSYCBwYWNrYWdlczogYGZhYmxlYCBhbmQgYG1vZGVsdGltZWAuDQoNCiMjIGBmYWJsZWAgYW5kIHRoZSB0aWR5dmVyKip0cyoqIGVjb3N5c3RlbQ0KDQpBIGdlbmVyYWxpemVkIGZ1bmN0aW9uIHRvIG9idGFpbiBmb3JlY2FzdHMgdmlhIGBmYWJsZWAgaXMgc2hvd24gYmVsb3cuIE9uZSBtdXN0IHNwZWNpZnkgdGhlIG1vZGVsIHdpdGggYXMgbXVjaCBjdXN0b21pemF0aW9uIGFzIG5lZWRlZC4NCg0KYGBge3IgZmFibGUtZnVuY3Rpb259DQpmYWJsZV93b3JrZmxvdyA8LSBmdW5jdGlvbihkYXRhID0gZGF0b3MsIG1vZGVsLCBsYWcgPSAxMCwgZG9mID0gMCwgaG9yaXpvbiA9IDMwLCB5ZWFyID0gMjAxOCl7DQogICMgU3BsaXR0aW5nIGRhdGEgaW50byB0cmFpbiBhbmQgdGVzdCBzZXRzDQogIHRyYWluIDwtIGRhdGEgJT4lIA0KICAgIHNsaWNlX2hlYWQobiA9IChucm93KGRhdGEpIC0gaG9yaXpvbikpDQoNCiAgdGVzdCA8LSBkYXRvcyAlPiUgDQogICAgc2xpY2VfdGFpbChuID0gaG9yaXpvbikNCg0KICAjIGZpdHRpbmcgdGhlIG1vZGVsDQogIGZhYmxlIDwtIHRyYWluICU+JQ0KICAgIG1vZGVsKG1vZGVsKQ0KICANCiAgcHJpbnQoIlRoZSBmaXR0ZWQgbW9kZWw6IikNCiAgZmFibGUgJT4lIA0KICAgIHJlcG9ydCgpDQogIA0KICBwcmludCgiVHJhaW5pbmcgYWNjdXJhY3k6IikNCiAgZmFibGUgJT4lIA0KICAgIGZhYmxldG9vbHM6OmFjY3VyYWN5KCkgJT4lIA0KICAgIHByaW50KCkNCiAgDQogICMgUmVzaWR1YWwgZGlhZ25vc3RpY3M6DQogIHJlc2lkcyA8LSBmYWJsZSAlPiUgDQogICAgZ2dfdHNyZXNpZHVhbHMoKSArDQogICAgZ2d0aXRsZSgiUmVzaWR1YWwgZGlhZ25vc3RpY3MiKQ0KICBwcmludChyZXNpZHMpDQogIA0KICBwcmludCgiUG9ydG1hbnRlYXUgdGVzdHMgZm9yIGF1dG9jb3JyZWxhdGlvbiIpDQogIGZhYmxlICU+JSANCiAgICBhdWdtZW50KCkgJT4lIA0KICAgIGZlYXR1cmVzKC5yZXNpZCwgbGp1bmdfYm94LCBsYWcgPSBsYWcsIGRvZiA9IGRvZikgJT4lIA0KICAgIHByaW50KCkNCiAgDQogIA0KICBwcmludCgiVGhlIGZvcmVjYXN0OiIpDQogIGZhYmxlX2Zjc3QgPC0gZmFibGUgJT4lIA0KICAgIGZvcmVjYXN0KGggPSBob3Jpem9uKQ0KICBwcmludChmYWJsZV9mY3N0KQ0KICANCiAgIyBQbG90dGluZyB0aGUgZm9yZWNhc3Q6DQogIGZjc3QgPC0gDQogICAgIyBIaXN0b3JpYyBkYXRhIHZzLiBmb3JlY2FzdA0KICAgIGZhYmxlX2Zjc3QgJT4lIA0KICAgIGF1dG9wbG90KGRhdGEpIC8gDQogICAgIyByZWNlbnQgaGlzdG9yeSB2cy4gZm9yZWNhc3QNCiAgICBmYWJsZV9mY3N0ICU+JSANCiAgICBhdXRvcGxvdChkYXRhICU+JSBmaWx0ZXIoeWVhcihmZWNoYSk+eWVhcikpICsNCiAgICBwbG90X2Fubm90YXRpb24odGl0bGUgPSAiVGhlIEZvcmVjYXN0IikNCiAgcHJpbnQoZmNzdCkNCiAgDQogIHByaW50KCJGb3JlY2FzdCBhY2N1cmFjeToiKQ0KICBmYWJsZV9mY3N0ICU+JSANCiAgICBmYWJsZXRvb2xzOjphY2N1cmFjeSh0ZXN0KSAlPiUgDQogICAgcHJpbnQoKQ0KICANCn0NCmBgYA0KDQoNCg0KIyMgYG1vZGVsdGltZWA6IGFuZCBleHRlbnNpb24gdG8gdGhlIGB0aWR5bW9kZWxzYA0KDQoNCiMgVGhlIG1vZGVscw0KDQpCZWxvdyB3ZSBpbXBsZW1lbnQgbWFueSBvZiB0aGUgbW9kZWxzIGF2YWlsYWJsZSBpbiBib3RoIHBhY2thZ2VzLg0KDQojIyBUaW1lIHNlcmllcyBkZWNvbXBvc2l0aW9uIHsudGFic2V0IC50YWJzZXQtZmFkZX0NCg0KIyMjIC4NCg0KVGhlcmUgYXJlIG1hbnkgZGVjb21wb3NpdGlvbiBtZXRob2RzLg0KDQojIyMgYGZhYmxlYA0KDQojIyMjIENsYXNzaWNhbCBkZWNvbXBvc2l0aW9uDQoNCmBgYHtyfQ0KZGF0b3MgJT4lIA0KICBtb2RlbChjbGFzc2ljYWxfZGVjb21wb3NpdGlvbihNV2gsIHR5cGUgPSAibXVsdGlwbGljYXRpdmUiKSkgJT4lIA0KICBjb21wb25lbnRzKCkgJT4lIA0KICBhdXRvcGxvdCgpICsgeGxhYigieWVhciIpICsNCiAgZ2d0aXRsZSgiQ2xhc3NpY2FsIGFkZGl0aXZlIGRlY29tcG9zaXRpb24iKQ0KYGBgDQojIyMjIFNUTCBkZWNvbXBvc2l0aW9uDQoNCkFuIFNUTCBkZWNvbXBvc2l0aW9uIGlzIG9idGFpbmVkIHdpdGggdGhlIGZvbGxvd2luZyBjb2RlLg0KDQpgYGB7cn0NCmRhdG9zICU+JSANCiAgbW9kZWwoU1RMKE1XaCkpICU+JSANCiAgY29tcG9uZW50cygpICU+JSANCiAgYXV0b3Bsb3QoKSArIHhsYWIoInllYXIiKSArDQogIGdndGl0bGUoIlNUTCBkZWNvbXBvc2l0aW9uIikNCmBgYA0KDQpUaGUgbXVsdGlwbGUgU1RMIGRlY29tcG9zaXRpb24gY2FuIGJlIGN1c3RvbWl6ZWQuIEluIHRoaXMgY2FzZSwgd2Ugd2FudCB0byBtYWtlIHRoZSB0cmVuZCBzbW9vdGhlci4NCg0KDQpgYGB7cn0NCmRhdG9zICU+JSANCiAgbW9kZWwoU1RMKE1XaCB+IHRyZW5kKHdpbmRvdyA9IDE4MykpKSAlPiUgDQogIGNvbXBvbmVudHMoKSAlPiUgDQogIGF1dG9wbG90KCkgKyB4bGFiKCJ5ZWFyIikgKw0KICBnZ3RpdGxlKCJTVEwgZGVjb21wb3NpdGlvbiIpDQpgYGANCg0KV2UgY291bGQgc2V0IHRoZSBzZWFzb25hbGl0eSB0byBiZSBmaXhlZCBzcGVjaWZ5aW5nIGBzZWFzb24od2luZG93ID0gJ3BlcmlvZGljJylgLg0KDQpgYGB7cn0NCmRhdG9zICU+JSANCiAgbW9kZWwoU1RMKE1XaCB+IHRyZW5kKHdpbmRvdyA9IDE4MykgKyANCiAgICAgICAgICAgICAgc2Vhc29uKHdpbmRvdyA9ICdwZXJpb2RpYycpKSkgJT4lIA0KICBjb21wb25lbnRzKCkgJT4lIA0KICBhdXRvcGxvdCgpICsgeGxhYigieWVhciIpICsNCiAgZ2d0aXRsZSgiU1RMIGRlY29tcG9zaXRpb24iKQ0KYGBgDQoNCiogTW9kZWxpbmcgYW5kIGZvcmVjYXN0aW5nIHVzaW5nIFNUTCBhbmQgQVJJTUE6DQoNCmBgYHtyfQ0KZmFibGVfd29ya2Zsb3coZGF0YSA9IGRhdG9zLCANCiAgICAgICAgICAgICAgIG1vZGVsID0gZGVjb21wb3NpdGlvbl9tb2RlbCgNCiAgICAgICAgICAgICAgICAgU1RMKGJveF9jb3goTVdoLCBsYW1iZGEgPSBsYW1iZGEpIH4gdHJlbmQod2luZG93ID0gMTgzKSksDQogICAgICAgICAgICAgICAgIEFSSU1BKHNlYXNvbl9hZGp1c3QgfiBQRFEoMCwwLDApKQ0KICAgICAgICAgICAgICAgKSkNCmBgYA0KDQoqIFVzaW5nIFNUTCBhbmQgRVRTOg0KDQpgYGB7cn0NCmZhYmxlX3dvcmtmbG93KGRhdGEgPSBkYXRvcywgDQogICAgICAgICAgICAgICBtb2RlbCA9IGRlY29tcG9zaXRpb25fbW9kZWwoDQogICAgICAgICAgICAgICAgIFNUTChib3hfY294KE1XaCwgbGFtYmRhID0gbGFtYmRhKSB+IHRyZW5kKHdpbmRvdyA9IDE4MykpLA0KICAgICAgICAgICAgICAgICBFVFMoc2Vhc29uX2FkanVzdCB+IHNlYXNvbigiTiIpKQ0KICAgICAgICAgICAgICAgKSkNCmBgYA0KKiBVc2luZyBTVEwsIEFSSU1BLCBmb3VyaWVyOg0KDQpgYGB7cn0NCmZhYmxlX3dvcmtmbG93KGRhdGEgPSBkYXRvcywgDQogICAgICAgICAgICAgICBtb2RlbCA9IGRlY29tcG9zaXRpb25fbW9kZWwoDQogICAgICAgICAgICAgICAgIFNUTChib3hfY294KE1XaCwgbGFtYmRhID0gbGFtYmRhKSB+IHRyZW5kKHdpbmRvdyA9IDE4MykpLA0KICAgICAgICAgICAgICAgICBBUklNQShzZWFzb25fYWRqdXN0IH4gUERRKDAsMCwwKSksDQogICAgICAgICAgICAgICAgIFRTTE0oc2Vhc29uX3llYXIgfiBmb3VyaWVyKEsgPSAxMCwgcGVyaW9kID0gIjEgeWVhciIpKSwNCiAgICAgICAgICAgICAgICAgVFNMTShzZWFzb25fd2VlayB+IGZvdXJpZXIoSyA9IDIsIHBlcmlvZCA9ICIxIHdlZWsiKSkNCiAgICAgICAgICAgICAgICkpDQpgYGANCg0KDQojIyMgYG1vZGVsdGltZWANCg0KIyMjIHstfQ0KIyMgRXhwb25lbnRpYWwgc21vb3RoaW5nIHsudGFic2V0IC50YWJzZXQtZmFkZX0NCg0KIyMjIC4NCg0KIyMjIGBmYWJsZWANCg0KYGBge3IgZmFibGUtRVRTfQ0KZmFibGVfd29ya2Zsb3cobW9kZWwgPSBFVFMoTVdoLCBvcHRfY3JpdCA9ICJtc2UiKSwNCiAgICAgICAgICAgICAgIGhvcml6b24gPSAzMCwNCiAgICAgICAgICAgICAgIHllYXIgPSAyMDE4KQ0KYGBgDQoNCg0KDQojIyMgYG1vZGVsdGltZWANCg0KIyMjIHstfQ0KDQojIyBBUklNQSB7LnRhYnNldCAudGFic2V0LWZhZGV9DQoNCiMjIyAuDQoNCiMjIyBgZmFibGVgDQoNCmBgYHtyIGZhYmxlLWFyaW1hfQ0KZmFibGVfd29ya2Zsb3cobW9kZWwgPSBBUklNQShNV2gpLA0KICAgICAgICAgICAgICAgaG9yaXpvbiA9IDMwLA0KICAgICAgICAgICAgICAgeWVhciA9IDIwMTgpDQpgYGANCg0KDQoNCiMjIyBgbW9kZWx0aW1lYA0KDQojIyMgey19DQoNCiMjIExpbmVhciByZWdyZXNzaW9uIHsudGFic2V0fQ0KDQojIyMgLg0KDQojIyMgYGZhYmxlYA0KDQpgYGB7cn0NCmZhYmxlX3dvcmtmbG93KG1vZGVsID0gVFNMTShNV2ggfiB0cmVuZCgpICsgc2Vhc29uKCkpLA0KICAgICAgICAgICAgICAgaG9yaXpvbiA9IDMwLA0KICAgICAgICAgICAgICAgeWVhciA9IDIwMTgpDQpgYGANCg0KDQojIyMgYG1vZGVsdGltZWANCg0KIyMjIHstfQ0KDQojIyBEeW5hbWljIHJlZ3Jlc3Npb24gey50YWJzZXR9DQoNCiMjIyAuDQoNCiMjIyBgZmFibGVgDQoNCmBgYHtyfQ0KZmFibGVfd29ya2Zsb3cobW9kZWwgPSBBUklNQShNV2ggfiB0cmVuZCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWFzb24oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUERRKDAsMCwwKSksDQogICAgICAgICAgICAgICBob3Jpem9uID0gMzAsDQogICAgICAgICAgICAgICB5ZWFyID0gMjAxOCkNCmBgYA0KDQoNCiMjIyBgbW9kZWx0aW1lYA0KDQojIyMgey19DQoNCg0KIyMgSGFybW9uaWMgZHluYW1pYyByZWdyZXNzaW9uIHsudGFic2V0fQ0KDQojIyMgLg0KDQojIyMgYGZhYmxlYA0KDQpgYGB7cn0NCmZhYmxlX3dvcmtmbG93KG1vZGVsID0gQVJJTUEoYm94X2NveChNV2gsIGxhbWJkYSkgfiBmb3VyaWVyKHBlcmlvZCA9ICIxIHdlZWsiLCBLID0gMikgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3VyaWVyKHBlcmlvZCA9ICIxIHllYXIiLCBLID0gMTUpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQRFEoMCwwLDApKSwNCiAgICAgICAgICAgICAgIGhvcml6b24gPSAzMCwNCiAgICAgICAgICAgICAgIHllYXIgPSAyMDE4KQ0KYGBgDQoNCg0KYGBge3J9DQpmYWJsZV93b3JrZmxvdyhtb2RlbCA9IEFSSU1BKE1XaCB+IGZvdXJpZXIocGVyaW9kID0gIjEgd2VlayIsIEsgPSAyKSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvdXJpZXIocGVyaW9kID0gIjEgeWVhciIsIEsgPSAxNSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBEUSgwLDAsMCkpLA0KICAgICAgICAgICAgICAgaG9yaXpvbiA9IDMwLA0KICAgICAgICAgICAgICAgeWVhciA9IDIwMTgpDQpgYGANCg0KIyMjIGBtb2RlbHRpbWVgDQoNCiMjIyB7LX0NCg0KIyMgUHJvcGhldCB7LnRhYnNldH0NCg0KIyMjIC4NCg0KIyMjIGBmYWJsZWANCg0KYGBge3J9DQpmYWJsZV93b3JrZmxvdyhtb2RlbCA9IHByb3BoZXQoTVdoKSwNCiAgICAgICAgICAgICAgIGhvcml6b24gPSAzMCwNCiAgICAgICAgICAgICAgIHllYXIgPSAyMDE4KQ0KYGBgDQoNCiMjIyBgbW9kZWx0aW1lYA0KDQojIyMgey19DQoNCiMjIEZBU1NURVIgey50YWJzZXR9DQoNCiMjIyAuDQoNCiMjIyBgZmFibGVgDQoNCmBgYHtyfQ0KZmFibGVfd29ya2Zsb3cobW9kZWwgPSBmYXNzdGVyKE1XaCB+IGZvdXJpZXIocGVyaW9kID0gIjEgd2VlayIsIEsgPSAyKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3VyaWVyKHBlcmlvZCA9ICIxIHllYXIiLCBLID0gMTApKSwNCiAgICAgICAgICAgICAgIGhvcml6b24gPSAzMCwNCiAgICAgICAgICAgICAgIHllYXIgPSAyMDE4KQ0KYGBgDQoNCg0KIyMjIGBtb2RlbHRpbWVgDQoNCiMjIyB7LX0NCg0KIyMgTmV1cmFsIG5ldHdvcmsgYXV0b3JyZWdyZXNpb24gey50YWJzZXR9DQoNCiMjIyAuDQoNCiMjIyBgZmFibGVgDQoNCmBgYHtyfQ0KZmFibGVfd29ya2Zsb3cobW9kZWwgPSBkZWNvbXBvc2l0aW9uX21vZGVsKA0KICBTVEwoTVdoIH4gdHJlbmQod2luZG93ID0gMTgzKSksDQogIE5ORVRBUihzZWFzb25fYWRqdXN0KQ0KKSwNCiAgICAgICAgICAgICAgIGhvcml6b24gPSAzMCwNCiAgICAgICAgICAgICAgIHllYXIgPSAyMDE4KQ0KYGBgDQoNCg0KYGBge3J9DQpmYWJsZV93b3JrZmxvdyhtb2RlbCA9IE5ORVRBUihib3hfY294KE1XaCwgbGFtYmRhID0gbGFtYmRhKSksDQogICAgICAgICAgICAgICBob3Jpem9uID0gMzAsDQogICAgICAgICAgICAgICB5ZWFyID0gMjAxOCkNCmBgYA0KDQoNCiMjIyBgbW9kZWx0aW1lYA0KDQojIyMgey19DQoNCiMjIFRoZSBwcm9wb3NlZCBtb2RlbA0KDQoNCiMgQ29tcGFyaXNvbiBhY3Jvc3MgbW9kZWxzDQoNCiMjIFRyYWluaW5nIGFkanVzdG1lbnQNCg0KIyMgRm9yZWNhc3RpbmcgYWRqdXN0bWVudA0KDQojIyBDcm9zcy12YWxpZGF0aW9uDQoNCiMjIEZvcmVjYXN0cw0KDQoNCiMgQ29uY2x1c2lvbnMNCg0K